/**
 * ━━━━━━神兽出没━━━━━━
 * 　　　┏┓　　　┏┓
 * 　　┏┛┻━━━┛┻┓
 * 　　┃　　　　　　　┃
 * 　　┃　　　━　　　┃
 * 　　┃　┳┛　┗┳　┃
 * 　　┃　　　　　　　┃
 * 　　┃　　　┻　　　┃
 * 　　┃　　　　　　　┃
 * 　　┗━┓　　　┏━┛
 * 　　　　┃　　　┃神兽保佑, 永无BUG!
 * 　　　　┃　　　┃Code is far away from bug with the animal protecting
 * 　　　　┃　　　┗━━━┓
 * 　　　　┃　　　　　　　┣┓
 * 　　　　┃　　　　　　　┏┛
 * 　　　　┗┓┓┏━┳┓┏┛
 * 　　　　　┃┫┫　┃┫┫
 * 　　　　　┗┻┛　┗┻┛
 * ━━━━━━感觉萌萌哒━━━━━━
 */
package com.zkgengkun.filter;

import com.google.common.collect.Maps;
import com.zkgengkun.constant.LoginConstants;
import com.zkgengkun.constant.MapConstants;
import com.zkgengkun.jwt.Jwt;
import com.zkgengkun.support.json.Jacksons;
import com.zkgengkun.support.util.JedisUtil;
import com.zkgengkun.support.util.UrlUtil;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;

/**
 * @author gengshikun
 * @date 2017/8/21
 */
@Order(1)
@WebFilter(urlPatterns = "/jwt/auth/*")
@Component
public class JwtFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(filterConfig.getServletContext());
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("JWT Filter");

        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        // jwt_pass
//        String contextPath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath();
        String url = request.getRequestURI().toString();
        if (UrlUtil.isMatchUrl(url, MapConstants.JWT_PASS_MAP) || StringUtils.isEmpty(url)) {
            // url 验证通过
            filterChain.doFilter(request, response);
        } else {
            String jwtToken = request.getHeader("JWT_TOKEN");
            String expiresTime = request.getHeader("EXPIRES_TIME"); // 过期时间
            if(StringUtils.isBlank(jwtToken) || StringUtils.isBlank(expiresTime)) {
                // 未登录或参数错误 跳转登录页
                this.toSignIn(request, response);
            } else {
                String jwtJson = Jwts.parser()
                        .setSigningKey("jwtToken")
                        .parseClaimsJws(jwtToken)
                        .getBody()
                        .getSubject();

                Jwt jwt = Jacksons.json().fromJsonToObject(jwtJson, Jwt.class);

                if(StringUtils.equals(jwtJson, JedisUtil.getInstance().STRINGS.get("jwt_token:"+jwt.getUserId()))) {
                    // refresh 没过期,
                    if(jwt.getExpiresTime() == Integer.parseInt(expiresTime)) {
                        // 判断 expiresTime 是否过期
                        if(jwt.getExpiresTime() > System.currentTimeMillis()) {
                            // token 正常
                            request.setAttribute("userId", jwt.getUserId());
                            filterChain.doFilter(request, response);
                        } else {
                            // token 过期 刷新token
                            jwt.setExpiresTime(System.currentTimeMillis() + 1800000);

                            String jwtToken_new = Jwts.builder()
                                    .setSubject(Jacksons.json().fromObjectToJson(jwt))
                                    .signWith(SignatureAlgorithm.HS512, "jwtToken")
                                    .compact();

                            response.addHeader("JWT_TOKEN", jwtToken_new);

                            // 放入 redis 不刷新refresh
                            JedisUtil.getInstance().STRINGS.set("jwt_token:"+jwt.getUserId(), jwtToken_new);

                            request.setAttribute("userId", jwt.getUserId());
                            filterChain.doFilter(request, response);
                        }

                    } else {
                        // 参数错误 跳转登录页
                        this.toSignIn(request, response);
                    }
                } else {
                    // refresh 过期, 重新登录
                    this.toSignIn(request, response);
                }

            }

        }

    }

    @Override
    public void destroy() {

    }

    private void toSignIn(HttpServletRequest request, HttpServletResponse response) throws IOException {
        if (request.getHeader("x-requested-with") != null && request.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest")) {
            // 异步请求
            this.ajaxRequestError(request, response);
        } else {
            // 非异步请求
            response.sendRedirect("/jwt/auth_login");//未登录
        }
    }


    private void ajaxRequestError(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("application/json; charset=UTF-8");

        Map<String, Object> resultMap = Maps.newHashMap();
        resultMap.put("success", false);
        resultMap.put("errorCode", LoginConstants.ERROR_CODE_0003);      //未登录错误码
        resultMap.put("errorMsg", LoginConstants.ERROR_CODE_0003_MSG);   //未登录

        response.getWriter().write(Jacksons.json().fromObjectToJson(resultMap));
    }
}

